package Core.plugin

import Core.{CPUSimple, Plugin}
import spinal.core._
import spinal.lib._
import Core._
import Core._
import Core._

import scala.language.postfixOps

case class RegFileReadPorts(XLEN : Int = 32) extends Bundle with IMasterSlave{
    val rs1_value = Bits(XLEN bits)
    val rs2_value = Bits(XLEN bits)
    val rs1_addr  = UInt(5 bits)
    val rs2_addr  = UInt(5 bits)
    val rs1_req   = Bool()
    val rs2_req   = Bool()

    override def asMaster(): Unit = {
        out(rs1_req, rs2_req, rs1_addr, rs2_addr)
        in(rs1_value, rs2_value)
    }
}

case class RegFileWritePorts(XLEN : Int = 32) extends Bundle with IMasterSlave{
    val rd_value = Bits(XLEN bits)
    val rd_addr  = UInt(5 bits)
    val rd_wen   = Bool()

    override def asMaster(): Unit = {
        out(rd_addr, rd_wen, rd_value)
    }
}

case class RegFileModule(XLEN : Int = 32) extends Component{
    val read_ports = slave(RegFileReadPorts(XLEN))
    val write_ports= slave(RegFileWritePorts(XLEN))

    val reg_file = Vec(Reg(Bits(XLEN bits)) init(0), 32).setName("reg_file")
    val read_value_1 = reg_file(read_ports.rs1_addr)
    val read_value_2 = reg_file(read_ports.rs2_addr)
    when(write_ports.rd_wen && write_ports.rd_addr=/=U(0, 5 bits)){
        reg_file(write_ports.rd_addr) := write_ports.rd_value
    }

    read_ports.rs1_value := (write_ports.rd_wen && (write_ports.rd_addr===read_ports.rs1_addr && write_ports.rd_addr=/=U(0,5 bits)) && read_ports.rs1_req) ?
                            write_ports.rd_value | read_value_1
    read_ports.rs2_value := (write_ports.rd_wen && (write_ports.rd_addr===read_ports.rs2_addr && write_ports.rd_addr=/=U(0,5 bits)) && read_ports.rs2_req) ?
                            write_ports.rd_value | read_value_2
}

class DecodePlugin() extends Plugin[CPUSimple] {
    var hazard : ControlPorts = null

    override def setup(pipeline: CPUSimple): Unit = {
        import Core.LoongArch._
        import pipeline.config._

        hazard = pipeline.service(classOf[ControlService]).newControlPorts

    }

    override def build(pipeline: CPUSimple): Unit = {
        import pipeline._
        import pipeline.config._
        import Core.LoongArch._

        val regfile_module = new RegFileModule(XLEN)
        decode plug new Area {

            import decode._

            val pc = input(PC)
            val instruction = input(INSTRUCTION)
            val rs1 = Bits(XLEN bits)
            val rs2 = Bits(XLEN bits)
            val imm_all = IMMALL(instruction)
            val imm = Bits(XLEN bits)
            val rs1_req = Bool()
            val rs2_req = Bool()
            val rs1_addr = UInt(5 bits)
            val rs2_addr = UInt(5 bits)
            val rd_addr = UInt(5 bits)
            val rd_wen = Bool()
            val alu_ctrl = Bits(AluCtrlEnum.ADD.asBits.getWidth bits)
            val link_addr = Bits(XLEN bits)
            val fetch_dec_branch = Bool()
            val rs1_eq_rs2 = Bool()
            val rs1_ne_rs2 = Bool()
            val rs1_lt_rs2 = Bool()
            val rs1_ge_rs2 = Bool()
            val rs1_ltu_rs2 = Bool()
            val rs1_geu_rs2 = Bool()

            val pc_next = UInt(addressWidth bits)
            val is_jirl = Bool()
            val is_branch = Bool()
            val is_call= False
            val is_return = False
            val is_jump = False
            val is_bl = Bool()
            val redirect_pc_next = input(PC) + 4
            val redirect_valid = False
            val branch_history = RegInit(U(0, PredictorHistoryLen bits))

            val is_load = Bool()
            val is_store = Bool()
            val mem_ctrl = Bits(MemCtrlEnum.LD_B.asBits.getWidth bits)
            val mem_wdata = Bits(XLEN bits)
            val csr_ctrl = Bits(CsrCtrlEnum.CSRRD.asBits.getWidth bits)
            val csr_addr = Bits(14 bits)
            val csr_wen  = Bool()
            val is_csr = Bool()
            val csr_code = Bits(15 bits)
            val is_adef = (input(PC).asBits)(1 downto 0) =/= B(0, 2 bits)
            val is_ine = Bool()

            when (imm_all.imm12_unsigned_op) {
                imm := imm_all.imm12_usext
            } elsewhen(imm_all.imm12_signed_op) {
                imm := imm_all.imm12_sext
            } elsewhen(imm_all.imm5_op) {
                imm := imm_all.imm5_usext
            } elsewhen(imm_all.imm16_op) {
                imm := imm_all.imm16_sext
            } elsewhen(imm_all.imm26_op) {
                imm := imm_all.imm26_sext
            } elsewhen(imm_all.imm14_op) {
                imm := imm_all.imm14_sext
            } elsewhen(imm_all.imm_lui_or_pcaddu_op) {
                imm := instruction.mux(
                    LUI -> imm_all.imm_lui_or_pcaddu,
                    PCADDU -> (imm_all.imm_lui_or_pcaddu.asSInt + pc.asSInt).asBits,
                    default -> B(0, 32 bits)
                )
            } otherwise {
                imm := B(0, 32 bits)
            }


            alu_ctrl := instruction.mux(
                ORI -> AluCtrlEnum.OR.asBits,
                ANDI -> AluCtrlEnum.AND.asBits,
                XORI -> AluCtrlEnum.XOR.asBits,
                ADD -> AluCtrlEnum.ADD.asBits,
                ADDI -> AluCtrlEnum.ADD.asBits,
                SUB -> AluCtrlEnum.SUB.asBits,
                NOR -> AluCtrlEnum.NOR.asBits,
                AND -> AluCtrlEnum.AND.asBits,
                OR -> AluCtrlEnum.OR.asBits,
                XOR -> AluCtrlEnum.XOR.asBits,
                SLL -> AluCtrlEnum.SLL.asBits,
                SRL -> AluCtrlEnum.SRL.asBits,
                SRA -> AluCtrlEnum.SRA.asBits,
                SLLI -> AluCtrlEnum.SLL.asBits,
                SRLI -> AluCtrlEnum.SRL.asBits,
                SRAI -> AluCtrlEnum.SRA.asBits,
                SLT -> AluCtrlEnum.SLT.asBits,
                SLTU -> AluCtrlEnum.SLTU.asBits,
                JIRL -> AluCtrlEnum.JIRL.asBits,
                LUI -> AluCtrlEnum.ADD.asBits,
                PCADDU -> AluCtrlEnum.ADD.asBits,
                BL -> AluCtrlEnum.BL.asBits,
                LD_B -> AluCtrlEnum.ADD.asBits,
                LD_BU -> AluCtrlEnum.ADD.asBits,
                LD_H -> AluCtrlEnum.ADD.asBits,
                LD_HU -> AluCtrlEnum.ADD.asBits,
                LD_W -> AluCtrlEnum.ADD.asBits,
                ST_B -> AluCtrlEnum.ADD.asBits,
                ST_W -> AluCtrlEnum.ADD.asBits,
                ST_H -> AluCtrlEnum.ADD.asBits,
                LL -> AluCtrlEnum.ADD.asBits,
                SC -> AluCtrlEnum.ADD.asBits,
                default -> B(0, AluCtrlEnum.ADD.asBits.getWidth bits) //NOP
            )

            rs1_addr := instruction.mux(
                ORI -> instruction(rjRange).asUInt,
                ANDI -> instruction(rjRange).asUInt,
                XORI -> instruction(rjRange).asUInt,
                ADD -> instruction(rjRange).asUInt,
                ADDI -> instruction(rjRange).asUInt,
                SUB -> instruction(rjRange).asUInt,
                NOR -> instruction(rjRange).asUInt,
                AND -> instruction(rjRange).asUInt,
                OR -> instruction(rjRange).asUInt,
                XOR -> instruction(rjRange).asUInt,
                SLL -> instruction(rjRange).asUInt,
                SRL -> instruction(rjRange).asUInt,
                SRA -> instruction(rjRange).asUInt,
                SLLI -> instruction(rjRange).asUInt,
                SRLI -> instruction(rjRange).asUInt,
                SRAI -> instruction(rjRange).asUInt,
                SLT -> instruction(rjRange).asUInt,
                SLTU -> instruction(rjRange).asUInt,
                JIRL -> instruction(rjRange).asUInt,
                BEQ -> instruction(rjRange).asUInt,
                BNE -> instruction(rjRange).asUInt,
                BLT -> instruction(rjRange).asUInt,
                BLTU -> instruction(rjRange).asUInt,
                BGE -> instruction(rjRange).asUInt,
                BGEU -> instruction(rjRange).asUInt,
                LD_B -> instruction(rjRange).asUInt,
                LD_H -> instruction(rjRange).asUInt,
                LD_BU -> instruction(rjRange).asUInt,
                LD_HU -> instruction(rjRange).asUInt,
                LD_W -> instruction(rjRange).asUInt,
                ST_B -> instruction(rjRange).asUInt,
                ST_W -> instruction(rjRange).asUInt,
                ST_H -> instruction(rjRange).asUInt,
                LL -> instruction(rjRange).asUInt,
                SC -> instruction(rjRange).asUInt,
                CSRWR -> instruction(rdRange).asUInt,
                CSRXCHG -> instruction(rjRange).asUInt,
                default -> U(0, 5 bits)
            )

            rs1_req := instruction.mux(
                ORI -> True,
                ANDI -> True,
                XORI -> True,
                ADD -> True,
                ADDI -> True,
                SUB -> True,
                NOR -> True,
                AND -> True,
                OR -> True,
                XOR -> True,
                SLL -> True,
                SRL -> True,
                SRA -> True,
                SLLI -> True,
                SRLI -> True,
                SRAI -> True,
                SLT -> True,
                SLTU -> True,
                JIRL -> True,
                LUI -> True,
                PCADDU -> True,
                BEQ -> True,
                BNE -> True,
                BLT -> True,
                BLTU -> True,
                BGE -> True,
                BGEU -> True,
                LD_B -> True,
                LD_BU -> True,
                LD_H -> True,
                LD_HU -> True,
                LD_W -> True,
                ST_B -> True,
                ST_W -> True,
                ST_H -> True,
                LL -> True,
                SC -> True,
                CSRWR -> True,
                CSRXCHG -> True,
                default -> False
            )

            rs2_addr := instruction.mux(
                ADD -> instruction(rkRange).asUInt,
                SUB -> instruction(rkRange).asUInt,
                NOR -> instruction(rkRange).asUInt,
                AND -> instruction(rkRange).asUInt,
                OR -> instruction(rkRange).asUInt,
                XOR -> instruction(rkRange).asUInt,
                SLL -> instruction(rkRange).asUInt,
                SRL -> instruction(rkRange).asUInt,
                SRA -> instruction(rkRange).asUInt,
                SLT -> instruction(rkRange).asUInt,
                SLTU -> instruction(rkRange).asUInt,
                BEQ -> instruction(rdRange).asUInt,
                BNE -> instruction(rdRange).asUInt,
                BLT -> instruction(rdRange).asUInt,
                BLTU -> instruction(rdRange).asUInt,
                BGE -> instruction(rdRange).asUInt,
                BGEU -> instruction(rdRange).asUInt,
                ST_B -> instruction(rdRange).asUInt,
                ST_W -> instruction(rdRange).asUInt,
                ST_H -> instruction(rdRange).asUInt,
                SC -> instruction(rdRange).asUInt,
                CSRXCHG -> instruction(rdRange).asUInt,
                default -> U(0, 5 bits)
            )

            rs2_req := instruction.mux(
                ADD -> True,
                SUB -> True,
                NOR -> True,
                AND -> True,
                OR -> True,
                XOR -> True,
                SLL -> True,
                SRL -> True,
                SRA -> True,
                SLT -> True,
                SLTU -> True,
                BEQ -> True,
                BNE -> True,
                BLT -> True,
                BLTU -> True,
                BGE -> True,
                BGEU -> True,
                ST_B -> True,
                ST_H -> True,
                ST_W -> True,
                SC -> True,
                CSRXCHG -> True,
                default -> False
            )

            rd_addr := instruction.mux(
                ORI -> instruction(rdRange).asUInt,
                ANDI -> instruction(rdRange).asUInt,
                XORI -> instruction(rdRange).asUInt,
                ADD -> instruction(rdRange).asUInt,
                ADDI -> instruction(rdRange).asUInt,
                SUB -> instruction(rdRange).asUInt,
                NOR -> instruction(rdRange).asUInt,
                AND -> instruction(rdRange).asUInt,
                OR -> instruction(rdRange).asUInt,
                XOR -> instruction(rdRange).asUInt,
                SLL -> instruction(rdRange).asUInt,
                SRL -> instruction(rdRange).asUInt,
                SRA -> instruction(rdRange).asUInt,
                SLLI -> instruction(rdRange).asUInt,
                SRLI -> instruction(rdRange).asUInt,
                SRAI -> instruction(rdRange).asUInt,
                SLT -> instruction(rdRange).asUInt,
                SLTU -> instruction(rdRange).asUInt,
                JIRL -> instruction(rdRange).asUInt,
                LUI -> instruction(rdRange).asUInt,
                PCADDU -> instruction(rdRange).asUInt,
                BL -> U(1, 5 bits),
                LD_B -> instruction(rdRange).asUInt,
                LD_H -> instruction(rdRange).asUInt,
                LD_HU -> instruction(rdRange).asUInt,
                LD_BU -> instruction(rdRange).asUInt,
                LD_W -> instruction(rdRange).asUInt,
                LL -> instruction(rdRange).asUInt,
                CSRRD -> instruction(rdRange).asUInt,
                CSRWR -> instruction(rdRange).asUInt,
                CSRXCHG -> instruction(rdRange).asUInt,
                default -> U(0, 5 bits)
            )

            rd_wen := instruction.mux(
                ORI -> True,
                ANDI -> True,
                XORI -> True,
                ADD -> True,
                ADDI -> True,
                SUB -> True,
                NOR -> True,
                AND -> True,
                OR -> True,
                XOR -> True,
                SLL -> True,
                SRL -> True,
                SRA -> True,
                SLLI -> True,
                SRLI -> True,
                SRAI -> True,
                SLT -> True,
                SLTU -> True,
                JIRL -> True,
                LUI -> True,
                PCADDU -> True,
                BL -> True,
                LD_B -> True,
                LD_H -> True,
                LD_HU -> True,
                LD_BU -> True,
                LD_W -> True,
                LL -> True,
                CSRRD -> True,
                CSRWR -> True,
                CSRXCHG -> True,
                default -> False
            )


            regfile_module.read_ports.rs1_addr := rs1_addr
            regfile_module.read_ports.rs2_addr := rs2_addr
            regfile_module.read_ports.rs1_req := rs1_req
            regfile_module.read_ports.rs2_req := rs2_req
            
            rs1 := regfile_module.read_ports.rs1_value
            rs2 := regfile_module.read_ports.rs2_value
            insert(ALU_CTRL) := alu_ctrl
            insert(RD_WEN) := rd_wen
            insert(RD_ADDR) := rd_addr
            insert(RS1_REQ) := rs1_req
            insert(RS2_REQ) := rs2_req
            insert(RS1_ADDR) := rs1_addr
            insert(RS2_ADDR) := rs2_addr
            //hazard.rs1_from_mem := memaccess.arbitration.isValid && memaccess.output(RD_WEN) && memaccess.output(RD_ADDR) =/= U(0, 5 bits) && memaccess.output(RD_ADDR) === rs1_addr
            //hazard.rs2_from_mem := memaccess.arbitration.isValid && memaccess.output(RD_WEN) && memaccess.output(RD_ADDR) =/= U(0, 5 bits) && memaccess.output(RD_ADDR) === rs2_addr
            //hazard.rs1_from_ex := execute.arbitration.isValid && execute.output(RD_WEN) && execute.output(RD_ADDR) =/= U(0, 5 bits) && execute.output(RD_ADDR) === rs1_addr
            //hazard.rs2_from_ex := execute.arbitration.isValid && execute.output(RD_WEN) && execute.output(RD_ADDR) =/= U(0, 5 bits) && execute.output(RD_ADDR) === rs2_addr

            when (input(RS1_FROM_EX)) {
                insert(RS1) := execute.output(ALU_RESULT)
            } elsewhen(input(RS1_FROM_MEM)) {
                insert(RS1) := memaccess.output(RD)
            } elsewhen (rs1_req) {
                insert(RS1) := is_store ? (rs1.asSInt + imm.asSInt).asBits | rs1
            } otherwise {
                insert(RS1) := imm
            }

            when (input(RS2_FROM_EX)) {
                insert(RS2) := execute.output(ALU_RESULT)
            } elsewhen(input(RS2_FROM_MEM)) {
                insert(RS2) := memaccess.output(RD)
            } elsewhen (rs2_req) {
                insert(RS2) := rs2
            } otherwise {
                insert(RS2) := imm
            }

            rs1_eq_rs2 := input(RS1).asSInt === input(RS2).asSInt
            rs1_ne_rs2 := input(RS1).asSInt =/= input(RS2).asSInt
            rs1_lt_rs2 := input(RS1).asSInt < input(RS2).asSInt
            rs1_ltu_rs2 := input(RS1).asUInt < input(RS2).asUInt
            rs1_ge_rs2 := input(RS1).asSInt >= input(RS2).asSInt
            rs1_geu_rs2 := input(RS1).asUInt >= input(RS2).asUInt

            link_addr := instruction.mux(
                JIRL -> (pc.asSInt + S(4, 32 bits)).asBits,
                BL -> (pc.asSInt + S(4, 32 bits)).asBits,
                default -> B(0, 32 bits)
            )

            fetch_dec_branch := instruction.mux(
                BEQ -> rs1_eq_rs2,
                BNE -> rs1_ne_rs2,
                BLT -> rs1_lt_rs2,
                BLTU -> rs1_ltu_rs2,
                BGE -> rs1_ge_rs2,
                BGEU -> rs1_geu_rs2,
                default -> False
            )

            pc_next := instruction.mux(
                JIRL -> (imm.asSInt + insert(RS1).asSInt).asUInt,
                default -> (imm.asSInt + input(PC).asSInt).asUInt
            )

            is_jirl := (instruction === JIRL) ? True | False
            is_branch := instruction.mux(
                BEQ -> True,
                BNE -> True,
                BLT -> True,
                BLTU -> True,
                BGE -> True,
                BGEU -> True,
                default -> False
            )
            is_bl := (instruction === BL) ? True | False


            when(is_jirl || is_branch) {
                when(is_jirl || fetch_dec_branch) {
                    when(!input(PREDICT_TAKEN) || input(PC_NEXT) =/= pc_next) {
                        redirect_valid := True
                        redirect_pc_next := pc_next
                    }
                } .otherwise {
                    redirect_valid := True
                    redirect_pc_next := input(PC) + 4
                }
            }

            when(is_jirl) {
                when(rd_addr === U(0)) {
                    when(rs1_addr === U(1) && imm === B(0)) {
                        is_return := True
                        is_call := False
                        is_jump := False
                    } .otherwise {
                        is_jump := True
                        is_call := False
                        is_return := False
                    }
                } .otherwise {
                    is_call := True
                    is_jump := False
                    is_return := False
                }
            } .elsewhen(is_bl) {
                is_call := True
                is_jump := False
                is_return := False
            } .otherwise {
                is_call := False
                is_jump := True
                is_return := False
            }

            when(arbitration.isFiring) {
                branch_history := (branch_history(PredictorHistoryLen-2 downto 0).asBits ## (is_jirl || fetch_dec_branch)).asUInt
            }

            insert(BRANCH_OR_JUMP) := (is_jirl || is_branch) && arbitration.isFiring
            insert(BRANCH_TAKEN) := is_jirl || fetch_dec_branch
            insert(LINK_ADDR) := link_addr
            insert(REDIRECT_VALID) := redirect_valid
            insert(REDIRECT_PC_NEXT) := redirect_pc_next
            insert(IS_CALL) := is_call
            insert(IS_JUMP) := is_jump
            insert(IS_RETURN) := is_return
            insert(BRANCH_HISTORY) := branch_history

            mem_ctrl := instruction.mux(
                LD_B -> MemCtrlEnum.LD_B.asBits,
                LD_H -> MemCtrlEnum.LD_H.asBits,
                LD_W -> MemCtrlEnum.LD_W.asBits,
                LD_BU -> MemCtrlEnum.LD_BU.asBits,
                LD_HU -> MemCtrlEnum.LD_HU.asBits,
                ST_B -> MemCtrlEnum.ST_B.asBits,
                ST_H -> MemCtrlEnum.ST_H.asBits,
                ST_W -> MemCtrlEnum.ST_W.asBits,
                default -> B(0, MemCtrlEnum.LD_W.asBits.getBitsWidth bits)
            )

            mem_wdata := instruction.mux(
                ST_B -> rs2,
                ST_H -> rs2,
                ST_W -> rs2,
                default -> B(0, 32 bits)
            )

            is_load := instruction.mux(
                LD_B -> True,
                LD_H -> True,
                LD_W -> True,
                LD_BU -> True,
                LD_HU -> True,
                LL -> True,
                default -> False
            )

            is_store := instruction.mux(
                ST_B -> True,
                ST_H -> True,
                ST_W -> True,
                SC -> True,
                default -> False
            )

            insert(MEM_CTRL) := mem_ctrl
            insert(IS_LOAD) := is_load
            insert(IS_STORE) := is_store
            insert(MEM_WDATA) := mem_wdata

            is_ine := instruction.mux(
                ORI -> False,
                ANDI -> False,
                XORI -> False,
                ADD -> False,
                ADDI -> False,
                SUB -> False,
                NOR -> False,
                AND -> False,
                OR -> False,
                XOR -> False,
                SLL -> False,
                SRL -> False,
                SRA -> False,
                SLLI -> False,
                SRLI -> False,
                SRAI -> False,
                SLT -> False,
                SLTU -> False,
                JIRL -> False,
                LUI -> False,
                PCADDU -> False,
                BEQ -> False,
                BNE -> False,
                BLT -> False,
                BLTU -> False,
                BGE -> False,
                BGEU -> False,
                LD_B -> False,
                LD_BU -> False,
                LD_H -> False,
                LD_HU -> False,
                LD_W -> False,
                ST_B -> False,
                ST_W -> False,
                ST_H -> False,
                LL -> False,
                SC -> False,
                CSRWR -> False,
                CSRXCHG -> False,
                CSRRD -> False,
                ERTN -> False,
                BREAK -> False,
                SYSCALL -> False,
                BRANCH_B -> False,
                BL -> False,
                default -> True
            )

            when(!is_adef) {
                when(!is_ine) {
                    csr_ctrl := instruction.mux(
                        CSRRD -> instruction(rkRange).mux(
                            B(0, 5 bits) -> CsrCtrlEnum.CSRRD.asBits,
                            B(1, 5 bits) -> CsrCtrlEnum.CSRWR.asBits,
                            default -> CsrCtrlEnum.CSRXCHG.asBits),
                        ERTN -> CsrCtrlEnum.ERTN.asBits,
                        SYSCALL -> CsrCtrlEnum.SYSCALL.asBits,
                        BREAK -> CsrCtrlEnum.BREAK.asBits,
                        default -> B(0, CsrCtrlEnum.ERTN.asBits.getWidth bits)
                    )
                } .otherwise {
                    csr_ctrl := CsrCtrlEnum.INE.asBits
                }
            } .otherwise {
                csr_ctrl := CsrCtrlEnum.ADEF.asBits
            }

            csr_addr := instruction(csrAddr)

            csr_wen := instruction.mux(
                CSRRD -> instruction(rkRange).mux(
                    B(0, 5 bits) -> False,
                    default -> True),
                default -> False
            )

            is_csr := instruction.mux(
                CSRRD -> True,
                default -> False
            )

            csr_code := instruction.mux(
                SYSCALL -> instruction(14 downto 0),
                default -> B(0, 15 bits)
            )


            insert(CSR_CTRL) := csr_ctrl
            insert(CSR_ADDR) := csr_addr
            insert(CSR_WEN) := csr_wen
            insert(IS_CSR) := is_csr
            insert(CSR_CODE) := csr_code

            writeback plug new Area {
                import writeback._
                regfile_module.write_ports.rd_wen := arbitration.isFiring & output(RD_WEN)
                regfile_module.write_ports.rd_addr := output(RD_ADDR)
                regfile_module.write_ports.rd_value := output(RD)
            }



        /**
         * val pc = input(PC)
         * val instruction = input(INSTRUCTION)
         * val rj = Bits(32 bits)
         * val rk = Bits(32 bits)
         * val imm_all = IMMALL(instruction)
         * val imm = Bits(32 bits)
         * val rj_req = !imm_all.imm26_op
         * val rk_req = !(imm_all.imm12_signed_op || imm_all.imm12_unsigned_op ||
         * imm_all.imm16_op || imm_all.imm26_op)
         * val rj_addr = instruction(rjRange).asUInt
         * val rk_addr = instruction(rkRange).asUInt
         * val rd_addr = instruction(rdRange).asUInt
         * val rd_wen = Bool()
         * val alu_ctrl = Bits(AluCtrlEnum.ADD.asBits.getWidth bits)
         * val src2_is_imm = imm_all.imm12_signed_op || imm_all.imm12_unsigned_op || imm_all.imm16_op || imm_all.imm16_op
         *
         * when(imm_all.imm5_op) {
         * imm := imm_all.imm5_usext
         * } .elsewhen(imm_all.imm12_signed_op) {
         * imm := imm_all.imm12_sext
         * } .elsewhen(imm_all.imm12_unsigned_op) {
         * imm := imm_all.imm12_usext
         * } .elsewhen(imm_all.imm16_op) {
         * imm := imm_all.imm16_sext
         * } .elsewhen(imm_all.imm26_op) {
         * imm := imm_all.imm26_sext
         * }
         *
         * alu_ctrl := instruction.mux(
         * ADD -> AluCtrlEnum.ADD.asBits,
         * ADDI -> AluCtrlEnum.ADD.asBits,
         * SUB -> AluCtrlEnum.SUB.asBits,
         * SLT -> AluCtrlEnum.SLT.asBits,
         * SLTI -> AluCtrlEnum.SLT.asBits,
         * SLTU -> AluCtrlEnum.SLTU.asBits,
         * SLTUI -> AluCtrlEnum.SLTU.asBits,
         * AND -> AluCtrlEnum.AND.asBits,
         * ANDI -> AluCtrlEnum.AND.asBits,
         * OR -> AluCtrlEnum.OR.asBits,
         * ORI -> AluCtrlEnum.OR.asBits,
         * XOR -> AluCtrlEnum.XOR.asBits,
         * XORI -> AluCtrlEnum.XOR.asBits,
         * NOR -> AluCtrlEnum.NOR.asBits,
         * SLL -> AluCtrlEnum.SLL.asBits,
         * SRL -> AluCtrlEnum.SRL.asBits,
         * SRA -> AluCtrlEnum.SRA.asBits,
         * SLLI -> AluCtrlEnum.SLL.asBits,
         * SRLI -> AluCtrlEnum.SRL.asBits,
         * SRAI -> AluCtrlEnum.SRA.asBits,
         * MUL -> AluCtrlEnum.MUL.asBits,
         * MULH -> AluCtrlEnum.MULH.asBits,
         * MULHU -> AluCtrlEnum.MULHU.asBits,
         * DIV -> AluCtrlEnum.DIV.asBits,
         * DIVU -> AluCtrlEnum.DIVU.asBits,
         * ST_B -> AluCtrlEnum.ADD.asBits,
         * ST_H -> AluCtrlEnum.ADD.asBits,
         * ST_W -> AluCtrlEnum.ADD.asBits,
         * JIRL -> AluCtrlEnum.JIRL.asBits,
         * BEQ -> AluCtrlEnum.BEQ.asBits,
         * BNE -> AluCtrlEnum.BNE.asBits,
         * BLT -> AluCtrlEnum.BLT.asBits,
         * BGE -> AluCtrlEnum.BGE.asBits,
         * BLTU -> AluCtrlEnum.BLTU.asBits,
         * BGEU -> AluCtrlEnum.BGEU.asBits,
         * )
         *
         * regfile_module.read_ports.rj_addr := rj_addr
         * regfile_module.read_ports.rk_addr := rk_addr
         * regfile_module.read_ports.rj_req := rj_req
         * regfile_module.read_ports.rk_req := rk_req
         * rj := regfile_module.read_ports.rj_value
         * rk := regfile_module.read_ports.rk_value
         * rd_wen := !imm_all.NOTWRITE;
         * insert(IMM) := imm
         * insert(RJ) := rj
         * insert(RK) := rk
         * insert(RJ_ADDR) := rj_addr
         * insert(RK_ADDR) := rk_addr
         * insert(ALU_CTRL) := alu_ctrl
         * } */
        }
    }
}
